import Taro from '@tarojs/taro';

function getAuthorization() {
  const app = Taro.getApp();
  const header = !!app.token ? { Authorization: "Bearer " + app.token } : null;

  return header;
}

//利用js原生的方法date.toLocaleString("sv-SE")，返回的是瑞士的格式，也就是返回YYYY-MM-DD HH:MM:SS这样的时间格式，和以下formatTime方法相同
function localTimeStr(date: Date) {
  return date.toLocaleString("sv-SE");
}

//返回YYYY-MM-DD HH:MM:SS这样的时间格式
function formatTime(date: Date): string {
  const year = date.getFullYear();
  const month = date.getMonth() + 1;
  const day = date.getDate();
  const hour = date.getHours();
  const minute = date.getMinutes();
  const second = date.getSeconds();
  return (
    [year, month, day].map(formatNumber).join("-") +
    " " +
    [hour, minute, second].map(formatNumber).join(":")
  );
}

//返回YYYY-MM-DD这样的时间格式
function formatTimeDate(date: Date): string {
  const year = date.getFullYear();
  const month = date.getMonth() + 1;
  const day = date.getDate();
  return (
    [year, month, day].map(formatNumber).join("-")
  );
}

//返回YYYY-MM-DD HH:MM这样的时间格式
function formatTimes(date: Date): string {
  const year = date.getFullYear();
  const month = date.getMonth() + 1;
  const day = date.getDate();
  const hour = date.getHours();
  const minute = date.getMinutes();
  return (
    [year, month, day].map(formatNumber).join("-") +
    " " +
    [hour, minute].map(formatNumber).join(":")
  );
}

//简化版本，只返回时间，不包括日期
function formatTimeLite(date: Date): string {
  const month = date.getMonth() + 1;
  const day = date.getDate();
  const hour = date.getHours();
  const minute = date.getMinutes();
  return (
    [month, day].map(formatNumber).join("-") +
    " " +
    [hour, minute,].map(formatNumber).join(":")
  );
}

function formatNumber(n: number): string {
  const tempStr = n.toString();
  return tempStr[1] ? tempStr : "0" + tempStr;
}

//jwt内容解析
function jwtDecode(jwt: string): {
  header: string,
  payload: string,
  signature: string
} {
  function b64DecodeUnicode(str: string) {
    return decodeURIComponent(
      Buffer.from(str, 'base64')
        .toString('utf-8')
        .replace(/(.)/g, function (_m, p) {
          // console.log("m的值", m);
          let code = p
            .charCodeAt(0)
            .toString(16)
            .toUpperCase();
          if (code.length < 2) {
            code = "0" + code;
          }
          return "%" + code;
        })
    );
  }

  function decode(str: string) {
    let output = str.replace(/-/g, "+").replace(/_/g, "/");
    switch (output.length % 4) {
      case 0:
        break;
      case 2:
        output += "==";
        break;
      case 3:
        output += "=";
        break;
      default:
        throw new Error("Illegal base64url string!");
    }

    try {
      return b64DecodeUnicode(output);
    } catch (err) {
      return Buffer.from(output, 'base64')
        .toString('utf-8')
    }
  }

  const jwtArray = jwt.split(".");

  return {
    header: decode(jwtArray[0]),
    payload: decode(jwtArray[1]),
    signature: decode(jwtArray[2])
  }
}

function showLoading(message?: string): void {
  if (!message) { message = "加载中..."; }
  if (Taro.showLoading) {    // 基础库 1.1.0 微信6.5.6版本开始支持，低版本需做兼容处理
    Taro.showLoading({
      title: message, mask: true
    });
  } else {    // 低版本采用Toast兼容处理并将时间设为20秒以免自动消失
    Taro.showToast({
      title: message, icon: 'loading', mask: true, duration: 20000
    });
  }
}

function hideLoading(): void {
  if (Taro.hideLoading) {    // 基础库 1.1.0 微信6.5.6版本开始支持，低版本需做兼容处理
    Taro.hideLoading();
  } else {
    Taro.hideToast();
  }
}

const toStr = Object.prototype.toString;

function isObject(value: Record<string, any>): boolean {
  return toStr.call(value) === '[object Object]';
}

//判断对象是否为空
function isObjEmpty(obj: Record<string, any>) {
  return !Object.getOwnPropertyNames(obj).length && !Object.getOwnPropertySymbols(obj).length;
}

function isArray(value: any): boolean {
  return toStr.call(value) === '[object Array]';
}

function isFunction(value: any): boolean {
  return typeof value === 'function';
}

function isNaN(value: any): boolean {
  return value !== value;
}

function isNumber(value: any): boolean {
  return typeof value === 'number' && !isNaN(value);
}

function isNull(value: any): boolean {
  return toStr.call(value) === '[object Null]';
}

function isBoolean(value: any): boolean {
  return typeof value === 'boolean';
}

function isString(value: any): boolean {
  return typeof value === 'string';
}

function isPromise(obj: any) {
  return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
}

//小程序用
function getLaunchOptions() {
  try {
    const options = Taro.getLaunchOptionsSync();
    return options;
  } catch (error) {
    console.error("getLaunchOptions error", error);
    return {} as Taro.getLaunchOptionsSync.LaunchOptions;
  }
}

function getRandomId() {
  // 时间戳（9位） + 随机串（10位）
  return (
    Date.now().toString(32) +
    Math.random()
      .toString(32)
      .substring(2)
  );
}

/**
 * 深拷贝
 * @param {object} obj 需要copy的对象
 */
function objectCopy(obj: Record<string, any>) {
  if (typeof obj === "undefined") {
    return obj;
  }
  return JSON.parse(JSON.stringify(obj));
}

/**
 * 给URL添加参数
 * @param url
 * @param params
 */
function addUrlParams(url = "", params: any) {
  url += url.indexOf("?") >= 0 ? "&" : "?";
  url += Object.keys(params)
    .map(key => {
      return `${key}=${params[key]}`;
    })
    .join("&");
  return url;
}

// 判断是否是json string
function isJSON(str: any) {
  if (typeof str === 'string') {
    try {
      const obj = JSON.parse(str)
      return !!(typeof obj === 'object' && obj)
    } catch (e) {
      return false
    }
  }
}

//检查对象是否属于某个自定义类型，入参1是对象，入参2是对象中的属性名
function isOfType<T>(
  varToBeChecked: any,
  propertyToCheckFor: keyof T
): varToBeChecked is T {
  return (varToBeChecked as T)[propertyToCheckFor] !== undefined;
}

/**
 * 将JSON转换成字符串
 * @param {object} obj 需要转换的对象
 */
function encodeJSON(obj: Record<string, any>) {
  try {
    return encodeURIComponent(JSON.stringify(obj));
  } catch (error) {
    console.error("encodeJSON error", error);
    return "";
  }
}

/**
 * 将字符串恢复成JSON
 * @param {string} str 需要转换的字符串
 */
function decodeJSON(str: string) {
  try {
    return JSON.parse(decodeURIComponent(str));
  } catch (error) {
    console.error("decodeJSON error", error);
    return "";
  }
}

//封装时分秒的格式
function formatSeconds(value) {
  let theTime = parseInt(value);// 秒
  let theTime1 = 0;// 分
  let theTime2 = 0;// 小时
  if (theTime > 60) {
    theTime1 = Math.round(theTime / 60);
    theTime = Math.round(theTime % 60);
    if (theTime1 > 60) {
      theTime2 = Math.round(theTime1 / 60);
      theTime1 = Math.round(theTime1 % 60);
    }
  }
  let result = "" + Math.ceil(theTime);
  if (parseInt(result) < 10) {
    result = '0' + result;
  }
  if (theTime1 > 0) {
    result = "" + Math.ceil(theTime1) + ":" + result;
    if (theTime1 < 10) {
      result = '0' + result;
    }
  } else {
    result = '00:' + result;
  }
  if (theTime2 > 0) {
    result = "" + Math.ceil(theTime2) + ":" + result;
    if (theTime2 < 10) {
      result = '0' + result;
    }
  } else {
    result = '00:' + result;
  }
  return result;
}

//封装分秒格式
function formatSecond(value) {
  let theTime = parseInt(value);// 秒
  let theTime1 = 0;// 分 
  if (theTime > 60) {
    theTime1 = Math.round(theTime / 60);
    theTime = Math.round(theTime % 60);
  }
  let result = "" + Math.ceil(theTime);
  if (parseInt(result) < 10) {
    result = '0' + result;
  }
  if (theTime1 > 0) {
    result = Math.ceil(theTime1) + ":" + result;
    if (theTime1 < 10) {
      result = '0' + result;
    }
  } else {
    result = '00:' + result;
  }
  return result;
}

//封装大额数值缩写为k、w函数
function numFormat(num: number) {
  let numStr = ''
  if (num >= 10000) {
    numStr = Math.round(num / 10000) + '万+'
  } else if (num >= 1000) {
    numStr = Math.round(num / 1000) + '千+'
  } else {
    numStr = Math.round(num) + ''
  }
  return numStr;
}

//比较两个对象的差别并返回
function getObjDiff(object: Record<string, any>, other: Record<string, any>) {
  const oldDeepCopy = JSON.parse(JSON.stringify(object));
  other = Object.assign(oldDeepCopy, other);

  const diff = {} as Record<string, any>;
  let vChildren: any
  for (const key in other) {
    if (!object[key] && !!other[key]) {
      //新对象有某个key，旧对象没有
      diff[key] = other[key];
    } else if (typeof object[key] === 'object' && typeof other[key] === 'object' && object[key] && other[key] && (object[key] instanceof Date === false)) {
      vChildren = getObjDiff(object[key], other[key])
      if (Object.keys(vChildren).length > 0) {
        diff[key] = vChildren
      }
    } else if (object[key] !== other[key]) {
      //如果新旧字段的值不一样，则取新对象的值
      // 日期格式需要做二次处理
      if (object[key] instanceof Date === true && JSON.stringify(object[key]) === JSON.stringify(other[key])) {
        return diff
      } else {
        diff[key] = other[key]
      }
    }
  }
  return diff
}

//FIXME 比较函数式组件的入参是否相等
function arePropsEqual(propsPrev: any, propsNext: any) {
  const isEqual = propsPrev.length === propsNext.length ? true : false;
  console.log("组件入参是否相同: ", isEqual)
  return isEqual;
}

//合并数组后去重
function mergeArrsUnique(arr1: any[], arr2: any[], prop: string) {
  const mergeArray = [...arr1, ...arr2];

  for (let i = 0; i < mergeArray.length; ++i) {
    for (let j = i + 1; j < mergeArray.length; ++j) {
      //确保数组对象包含指定属性
      if (!!Object.getOwnPropertyDescriptor(mergeArray[i], prop) && !!Object.getOwnPropertyDescriptor(mergeArray[j], prop)) {
        //按sequence去重
        if (mergeArray[i][prop] === mergeArray[j][prop]) {
          mergeArray.splice(j--, 1);
        }
      }
    }
  }

  return mergeArray;
}

export {
  getAuthorization,
  localTimeStr,
  formatTime,
  formatTimeDate,
  formatTimes,
  formatTimeLite,
  formatNumber,
  jwtDecode,
  showLoading,
  hideLoading,
  isObject,
  isObjEmpty,
  isArray,
  isFunction,
  isNaN,
  isNumber,
  isNull,
  isBoolean,
  isString,
  isPromise,
  isOfType,
  getLaunchOptions,
  getRandomId,
  objectCopy,
  addUrlParams,
  isJSON,
  encodeJSON,
  decodeJSON,
  formatSeconds,
  formatSecond,
  numFormat,
  getObjDiff,
  arePropsEqual,
  mergeArrsUnique,
};

export default {
  getAuthorization,
  localTimeStr,
  formatTime,
  formatTimeDate,
  formatTimes,
  formatTimeLite,
  formatNumber,
  jwtDecode,
  showLoading,
  hideLoading,
  isObject,
  isObjEmpty,
  isArray,
  isFunction,
  isNaN,
  isNumber,
  isNull,
  isBoolean,
  isString,
  isPromise,
  isOfType,
  getLaunchOptions,
  getRandomId,
  objectCopy,
  addUrlParams,
  isJSON,
  encodeJSON,
  decodeJSON,
  formatSeconds,
  formatSecond,
  numFormat,
  getObjDiff,
  arePropsEqual,
  mergeArrsUnique,
};